package com.cmcc.pcap.packet.udp.pfcp.xdr;

/*
 * @author        : Wang
 * @data          : 2023/5/1018:04
 * @description   : some description
 */

import com.alibaba.fastjson.JSONObject;
import com.cmcc.packet.entity.PfcpEntity;
import com.cmcc.pcap.packet.udp.UdpConnection;
import com.cmcc.pcap.packet.util.PacketAnalysisConfig;
import com.cmcc.pcap.packet.util.pfcpUtile.PfcpTypeFactory;
import com.cmcc.pcap.packet.util.pfcpUtile.PfcpTypeUtil;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

public class PfcpXdrGenerate {
    private static Logger logger = LogManager.getLogger(PfcpXdrGenerate.class);

    public List<PfcpEntity> generate(UdpConnection udpConnection, String taskId) {
        List<PfcpEntity> pfcpEntityList = new ArrayList<PfcpEntity>();
        logger.debug("this is pfcp xdr generate !");

        PfcpEntity pfcpEntity = new PfcpEntity();
        pfcpEntity.setTaskId(Integer.parseInt(taskId));
        pfcpEntity.setType("PFCP");

        try {
            pfcpEntityList=saveUdpConnectionToEntityList(udpConnection,pfcpEntity);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            logger.error(e.getCause(), e);
        } catch (Exception e) {
            logger.error(e.getCause(), e);
        }

        //将每个XdrEntity加入XdrEntityList中，调用SaveHttpTransactionInfo的save方法保存到数据库中
//        pfcpEntityList.add(pfcpEntity);


        return pfcpEntityList;
    }


    public List<PfcpEntity> saveUdpConnectionToEntityList(UdpConnection udpConnection, PfcpEntity pfcpEntity) throws ParseException, InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        List<PfcpEntity> pfcpEntityList=new ArrayList<>();
        if (udpConnection.al == null || udpConnection.al.size() == 0) {
            return null;
        }

        // 判断是否为initail 报文 通过longheader格式


        // 找到连接的connectionKey直接填写源地址和目的地址
        String[] connectionKey = udpConnection.connectionKey.split("-");
        String[] srcsocket = connectionKey[0].split(":");
        String[] dstsocket = connectionKey[1].split(":");


        Integer length = udpConnection.al.size();
        logger.debug("tcpConnection length:" + length);

        //填写payload
        //控制拿到payload的报文个数
        /*
         * 从配置文件中拿payload个数
         */
        Integer payloadNum = PacketAnalysisConfig.getConfigAsInt("tcp.payloads.num");
        byte[] payloads = new byte[]{};

        /*
         * 根据配置文件，控制拿payload的个数
         */
        Integer getPayloadLength = 0;
        if (payloadNum < udpConnection.al.size())
            getPayloadLength = payloadNum;
        else
            getPayloadLength = udpConnection.al.size();

        for (int i = 0; i < getPayloadLength; i++) {
            byte[] temp = udpConnection.al.get(i).udpPacket.getPayload().getRawData();
            PfcpEntity pet=new PfcpEntity();
            pet.setTimestamp(udpConnection.al.get(i).timestamp);
            pet.setSrcIp(udpConnection.al.get(i).ipPacket.getHeader().getSrcAddr().getHostAddress());
            String srcPort=udpConnection.al.get(i).udpPacket.getHeader().getSrcPort().toString();
            int bracketIndex=srcPort.indexOf("(");
            pet.setSrcPort((bracketIndex != -1) ? srcPort.substring(0, bracketIndex).trim() : srcPort);
            pet.setDstIp(udpConnection.al.get(i).ipPacket.getHeader().getDstAddr().getHostAddress());
            String dsrPort=udpConnection.al.get(i).udpPacket.getHeader().getDstPort().toString();
            bracketIndex=dsrPort.indexOf("(");
            pet.setDstPort((bracketIndex != -1) ? dsrPort.substring(0, bracketIndex).trim() : dsrPort);
            copyPropertiesWithoutNull(pet,pfcpEntity);
            copyPropertiesWithoutNull(pet,generatePfcpEntity(temp));
            pfcpEntityList.add(pet);
        }
        return pfcpEntityList;
    }

    private PfcpEntity generatePfcpEntity (byte[] payload) {
        PfcpEntity pfcpEntity = new PfcpEntity();
        StringBuffer sb = new StringBuffer();
        sb.append((payload[0]>>7)&0x1)
                .append((payload[0]>>6)&0x1)
                .append((payload[0]>>5)&0x1)
                .append((payload[0]>>4)&0x1)
                .append((payload[0]>>3)&0x1)
                .append((payload[0]>>2)&0x1)
                .append((payload[0]>>1)&0x1)
                .append((payload[0]>>0)&0x1);
        String flags = sb.toString();
        pfcpEntity.setFlags(flags);
        pfcpEntity.setVersion(String.valueOf(Integer.parseInt(flags.substring(0,3), 2 )));
        pfcpEntity.setFo(flags.substring(5,6));
        pfcpEntity.setMp(flags.substring(6,7));
        pfcpEntity.setS(flags.substring(7));

        pfcpEntity.setMessageType(String.valueOf((payload[1] & 0xff)));
        pfcpEntity.setLength(((payload[2] & 0xff) << 8)+(payload[3] & 0xff));
        int k =0;
        int m=0;
        int n=0;
        if(pfcpEntity.getS().equals("1")) {
            k =1;
            m=5;
            n=13;
            pfcpEntity.setSeid("0x"+ payload[4]+ payload[5]+ payload[6]+ payload[7]
                    + payload[8]+ payload[9]+ payload[10]+ payload[11]);
        }else if(pfcpEntity.getS().equals("0")) {
            k =0;
            m=0;
            n=5;
        }
        StringBuffer seid = new StringBuffer();
        seid.append("0x");
        // 确保m和k的值是有效的，并且SEID的起始位置和长度不超出payload的范围
        if (m >= 0 && k > 0 && m + k <= payload.length) {
            for (int i = m - 1; i < k * (m + 7); i++) {
                seid.append(payload[i]);
            }
        }
        pfcpEntity.setSequenceNum(String.valueOf(((payload[n-1] & 0xff) << 16)+((payload[n] & 0xff) << 8)+(payload[n+1] & 0xff)));
        if(pfcpEntity.getMp().equals("1")) {
            StringBuffer messagePriority = new StringBuffer();
            messagePriority.append((payload[n+2]>>7)&0x1)
                    .append((payload[n+2]>>6)&0x1)
                    .append((payload[n+2]>>5)&0x1)
                    .append((payload[n+2]>>4)&0x1);
            pfcpEntity.setMessagePriority(Integer.parseInt(messagePriority.toString(), 2 ));
        }

        int total_length = pfcpEntity.getLength()+4;
        int p = n+2;
        pfcpEntity.setIeList(new ArrayList<>());
        while(p < total_length-1) {
            int ie_type = ((payload[p+1] & 0xff) << 8) + (payload[p+2] & 0xff);
            int ie_length = ((payload[p+3] & 0xff) << 8) + (payload[p+4] & 0xff);
            PfcpEntity.InformationElement peie = new PfcpEntity.InformationElement();
            byte[] sub_payload = new byte[ie_length+4];
            System.arraycopy(payload, p+1, sub_payload, 0, ie_length+4);
            PfcpTypeUtil ptu = PfcpTypeFactory.getPfcpType(ie_type);
            if(ptu!=null)
            {
                peie = ptu.analysisIe(sub_payload);
                pfcpEntity.ieList.add(peie);
            }
            p += ie_length + 4;
        }
        String message = JSONObject.toJSONString(pfcpEntity);
        pfcpEntity.setMessage(message);
        return pfcpEntity;
    }
    private static void copyPropertiesWithoutNull(Object dest, Object orig) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        PropertyUtils.describe(orig).forEach((key, value) -> {
            if (value != null) {
                try {
                    BeanUtils.copyProperty(dest, key, value);
                } catch (IllegalAccessException | InvocationTargetException e) {
                    // Handle exception
                }
            }
        });
    }
}
